package com.zondy.mapgis.common.core.utils;

import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.BooleanNode;
import com.fasterxml.jackson.databind.node.IntNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.fasterxml.jackson.databind.node.ValueNode;
import com.zondy.mapgis.common.core.utils.spring.SpringUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @author luohua
 */
public class JsonUtils {
    private static final ObjectMapper OBJECT_MAPPER = SpringUtils.getBean(ObjectMapper.class);

    public static ObjectMapper getObjectMapper() {
        return OBJECT_MAPPER;
    }

    public static String toJsonString(Object object) {
        if (ObjectUtil.isNull(object)) {
            return null;
        } else {
            try {
                return OBJECT_MAPPER.writeValueAsString(object);
            } catch (JsonProcessingException var2) {
                throw new RuntimeException(var2);
            }
        }
    }

    public static <T> T parseObject(String text, Class<T> clazz) {
        if (StringUtils.isEmpty(text)) {
            return null;
        } else {
            try {
                return OBJECT_MAPPER.readValue(text, clazz);
            } catch (IOException var3) {
                throw new RuntimeException(var3);
            }
        }
    }

    public static <T> T parseObject(byte[] bytes, Class<T> clazz) {
        if (ArrayUtil.isEmpty(bytes)) {
            return null;
        } else {
            try {
                return OBJECT_MAPPER.readValue(bytes, clazz);
            } catch (IOException var3) {
                throw new RuntimeException(var3);
            }
        }
    }

    public static <T> T parseObject(String text, TypeReference<T> typeReference) {
        if (StringUtils.isBlank(text)) {
            return null;
        } else {
            try {
                return OBJECT_MAPPER.readValue(text, typeReference);
            } catch (IOException var3) {
                throw new RuntimeException(var3);
            }
        }
    }

    public static Dict parseMap(String text) {
        if (StringUtils.isBlank(text)) {
            return null;
        } else {
            try {
                return (Dict)OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructType(Dict.class));
            } catch (IOException var2) {
                throw new RuntimeException(var2);
            }
        }
    }

    public static List parseArrayMap(String text) {
        if (StringUtils.isBlank(text)) {
            return null;
        } else {
            try {
                return (List)OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, Dict.class));
            } catch (IOException var2) {
                throw new RuntimeException(var2);
            }
        }
    }

    public static <T> List<T> parseArray(String text, Class<T> clazz) {
        if (StringUtils.isEmpty(text)) {
            return new ArrayList();
        } else {
            try {
                return (List)OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz));
            } catch (IOException var3) {
                throw new RuntimeException(var3);
            }
        }
    }

    public static JsonNode toJsonNode(String text) {
        try {
            return OBJECT_MAPPER.readTree(text);
        } catch (IOException var2) {
            throw new RuntimeException(var2);
        }
    }

    public static boolean isJson(String text) {
        boolean result = false;
        if (StringUtils.isNotBlank(text)) {
            text = text.trim();
            if (text.startsWith("{") && text.endsWith("}")) {
                result = true;
            } else if (text.startsWith("[") && text.endsWith("]")) {
                result = true;
            }
        }

        return result;
    }

    public static void merge(JsonNode toBeMerged, JsonNode mergedInTo) {
        Iterator<Map.Entry<String, JsonNode>> incomingFieldsIterator = toBeMerged.fields();
        Iterator<Map.Entry<String, JsonNode>> mergedIterator = mergedInTo.fields();

        while(incomingFieldsIterator.hasNext()) {
            Map.Entry<String, JsonNode> incomingEntry = (Map.Entry)incomingFieldsIterator.next();
            JsonNode subNode = (JsonNode)incomingEntry.getValue();
            boolean newEntry;
            Map.Entry entry;
            if (subNode.getNodeType().equals(JsonNodeType.OBJECT)) {
                newEntry = true;
                mergedIterator = mergedInTo.fields();

                while(mergedIterator.hasNext()) {
                    entry = (Map.Entry)mergedIterator.next();
                    if (((String)entry.getKey()).equals(incomingEntry.getKey())) {
                        merge((JsonNode)incomingEntry.getValue(), (JsonNode)entry.getValue());
                        newEntry = false;
                    }
                }

                if (newEntry) {
                    ((ObjectNode)mergedInTo).replace((String)incomingEntry.getKey(), (JsonNode)incomingEntry.getValue());
                }
            } else if (subNode.getNodeType().equals(JsonNodeType.ARRAY)) {
                newEntry = true;
                mergedIterator = mergedInTo.fields();

                while(mergedIterator.hasNext()) {
                    entry = (Map.Entry)mergedIterator.next();
                    if (((String)entry.getKey()).equals(incomingEntry.getKey())) {
                        updateArray((JsonNode)incomingEntry.getValue(), entry);
                        newEntry = false;
                    }
                }

                if (newEntry) {
                    ((ObjectNode)mergedInTo).replace((String)incomingEntry.getKey(), (JsonNode)incomingEntry.getValue());
                }
            }

            ValueNode valueNode = null;
            JsonNode incomingValueNode = (JsonNode)incomingEntry.getValue();
            switch (subNode.getNodeType()) {
                case STRING:
                    valueNode = new TextNode(incomingValueNode.textValue());
                    break;
                case NUMBER:
                    valueNode = new IntNode(incomingValueNode.intValue());
                    break;
                case BOOLEAN:
                    valueNode = BooleanNode.valueOf(incomingValueNode.booleanValue());
            }

            if (valueNode != null) {
                updateObject(mergedInTo, (ValueNode)valueNode, incomingEntry);
            }
        }

    }

    private static void updateArray(JsonNode valueToBePlaced, Map.Entry<String, JsonNode> toBeMerged) {
        toBeMerged.setValue(valueToBePlaced);
    }

    private static void updateObject(JsonNode mergeInTo, ValueNode valueToBePlaced, Map.Entry<String, JsonNode> toBeMerged) {
        boolean newEntry = true;
        Iterator<Map.Entry<String, JsonNode>> mergedIterator = mergeInTo.fields();

        while(mergedIterator.hasNext()) {
            Map.Entry<String, JsonNode> entry = (Map.Entry)mergedIterator.next();
            if (((String)entry.getKey()).equals(toBeMerged.getKey())) {
                newEntry = false;
                entry.setValue(valueToBePlaced);
            }
        }

        if (newEntry) {
            ((ObjectNode)mergeInTo).replace((String)toBeMerged.getKey(), (JsonNode)toBeMerged.getValue());
        }

    }

    private JsonUtils() {
    }
}
